# -*- coding: utf-8 -*-
# @Time    : 2024/7/17 17:01
# @Author  : yujiahao
# @File    : 38_fastapi_sql_models.py
# @description:SQL (关系型) 数据库 创建数据库模型

import importlib
# todo 属性 0、导入依赖，属性类型
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
# todo 关系 0、创建关系
from sqlalchemy.orm import relationship

# 用Base类来创建 SQLAlchemy 模型
"""
我们将使用我们之前创建的 Base 类来创建 SQLAlchemy 模型。

Tip:
-----
SQLAlchemy 使用的“模型”这个术语来指代与数据库交互的这些类和实例。

而 Pydantic 也使用“模型”这个术语来指代不同的东西，即数据验证、转换以及文档类和实例。

从 database（来自上面的 37_fastapi_sql_database.py文件）导入 Base。

创建从它继承的类。

这些类就是 SQLAlchemy 模型。
"""

# Python 的模块命名规则不允许模块名以数字开头，这会导致语法错误或导入问题。所以使用动态导入模块这里注意一下
# from .37_fastapi_sql_database import Base
# todo 类 0、 动态导入模块
database_module = importlib.import_module('com.yujiahao.my_fastapi.37_fastapi_sql_database')
Base = database_module.Base


# todo 类 1、 创建从它继承的类，这些类就是 SQLAlchemy 模型
class User(Base):
    # 这个__tablename__属性是用来告诉 SQLAlchemy 要在数据库中为每个模型使用的数据库表的名称
    __tablename__ = "users"

    # todo 属性 1、创建模型属性/列
    """
    现在创建所有模型（类）的属性。

    这些属性中的每一个都代表其相应数据库表中的一列。

    我们使用 Column 来表示 SQLAlchemy 中的默认值。

    我们传递一个 SQLAlchemy “类型”，如 Integer、String 和 Boolean，它定义了数据库中的类型，作为参数。
    """

    id = Column(Integer, primary_key=True)
    email = Column(String(255), unique=True, index=True)
    hashed_password = Column(String(255))
    is_active = Column(Boolean, default=True)

    # todo 关系 2、使用SQLAlchemy ORM提供的relationship。
    # 这将或多或少会成为一种“神奇”属性，其中表示该表与其他相关的表中的值。

    """
    当访问 user 中的属性 items 时，如 my_user.items，它将有一个 Item SQLAlchemy 模型列表（来自 items 表），
    这些模型具有指向 users 表中此记录的外键。

    当访问 my_user.items 时，SQLAlchemy 实际上会从 items 表中获取一批记录并在此处填充进去。

    同样，当访问 Item 中的属性 owner 时，它将包含表中的 User SQLAlchemy 模型（来自 users 表）。
    使用 owner_id 属性/列及其外键来了解要从 users 表中获取哪条记录。
    """

    items = relationship("Item", back_populates="owner")


class Item(Base):
    __tablename__ = "items"

    id = Column(Integer, primary_key=True)
    title = Column(String(255), index=True)
    description = Column(String(255), index=True)
    owner_id = Column(Integer, ForeignKey("users.id"))
    """
    ForeignKey:

        owner_id = Column(Integer, ForeignKey("users.id")) 这一行代码定义了 items 表中的 owner_id 列，它是一个外键，引用了 users 表的 id 列。
        这意味着 items 表中的 owner_id 列必须包含 users 表中存在的 id 值。
    relationship:

        owner = relationship("User", back_populates="items") 这一行代码定义了 Item 模型中的 owner 属性，它实际上是一个关系属性。
        这个关系属性并不是数据库中的实际列，而是一个通过外键连接到 users 表的 User 模型实例。
        back_populates="items" 表示 User 模型中也有一个 items 属性，它通过这个关系反向引用 Item 模型。
    """
    owner = relationship("User", back_populates="items")
